//
//  WalletViewModel.swift
//  Wallet
//
//  Created by Julian on 2022/5/7.
//

import Foundation
import RxSwift
import RxCocoa

struct WalletViewModel {
    // MARK: - VARS
    let repo: WalletRepository
    
    let bag = DisposeBag()
    
    // MARK: - DATA
    // 货币信息
    private let coins: PublishSubject<[Coin]> = PublishSubject()
    // 汇率信息
    private let rate: PublishSubject<[String: [Tiers]]> = PublishSubject()
    
    // MARK: - STATE
    // - HEADER
    var totalAmount: BehaviorRelay<Double> = BehaviorRelay(value: 0.00)
    public var totalAmountDriver: Driver<Double> {
        return totalAmount.asDriver()
    }
    public var totalAmountValue: Double {
        return totalAmount.value
    }
    
    // - BODY
    private var coinDataSource: BehaviorRelay<[CoinViewModel]> = BehaviorRelay(value: [])
    public var dataSourceDriver: Driver<[CoinViewModel]> {
        return coinDataSource.asDriver()
    }
    public var dataSource: [CoinViewModel] {
        return coinDataSource.value
    }

    // MARK: - INITIALIZE
    init(with repo: WalletRepository) {
        self.repo = repo
    }
    
    // MARK: - PUBLIC METHODS
    func requestData() {
        Observable.combineLatest(coins, rate)
            .map { mergeCoinAndRate(coins: $0.0, rate: $0.1) }  //
            .subscribe(onNext: {
                self.coinDataSource.accept($0)
            })
            .disposed(by: bag)
        
        coinDataSource.map { viewModels in
            viewModels.reduce(0.0) {
                $0 + $1.currencyAmount
            }
        }.subscribe {
            totalAmount.accept($0)
        }.disposed(by: bag)
        
        // 获取用户所有的 coin
        self.repo.getWalletCoins()
            .subscribe { coins.onNext($0) }  // => [Coin]
            .disposed(by: bag)
        
        // 获取实时汇率
        self.repo.getLiveRate()
            .subscribe { rate.onNext($0) }  // => { "BTC": [Rate], "CRO": [Rate] }
            .disposed(by: bag)
    }
    
    // MARK: - PRIVATE METHODS
    private func mergeCoinAndRate(coins: [Coin], rate: [String: [Tiers]]) -> [CoinViewModel] {
        return coins.map {
            var result = $0
            result.rates = rate[$0.coinID]?.first  // => { "BTC": Tiers, "CRO": Tiers }
            return CoinViewModel(coin: result)
        }
    }
}
